from copy import deepcopy
from logging import getLogger
from xml.etree import ElementTree as etree

from zope.interface import implements
from zope.component import getSiteManager

from meercat.interfaces import IOrderedRegistry

from meercat.base.instance import Instance
from meercat.base.metadata import Metadata
from meercat.base.registry import OrderedRegistry

from meercat.harvester.base.interfaces import IFileSource
from meercat.harvester.base.exceptions import HarvesterException
from meercat.harvester.base import sources

from meercat.harvester.sfx.interfaces import *

import csv



log = getLogger('meercat.harvester.sfx')

class SfxHarvester(object):
    implements(ISFXHarvester)
    
    def __init__(self, source, **kwargs):
        self.source = source
        if kwargs.get('fileSource',None):
            self.fileSource = kwargs['fileSource']
        self.dialect = kwargs.get('dialect', 'excel-tab')
        self.identifier = kwargs.get('identifier',4)
        
        if kwargs.get('fieldsets',None):
            self.fieldsets = kwargs['fieldsets']
        else:
            utility = getSiteManager().queryUtility(ISFXDefaultFieldSets)
            if utility is not None:
                self.fieldsets = deepcopy(utility)
            else:
                self.fieldsets = OrderedRegistry(ISFXFieldSet)
    
    def getSource(self):
        return self.source

    def setSource(self, name):
        self.source = name
        
    def getFileSource(self):
        return self._fileSource
    
    def setFileSource(self, source):
        self._fileSource = IFileSource(source)
    
    fileSource = property(getFileSource, setFileSource)
    
    def getFieldsets(self):
        return self._fieldsets
    
    def setFieldsets(self, fieldsets):
        self._fieldsets = IOrderedRegistry(fieldsets)
    
    fieldsets = property(getFieldsets, setFieldsets)
    
    def harvest(self):
        log.debug('%s.harvest()' % (str(self),))
        
        fh = self.fileSource()
        
        if fh is None:
            log.error('No files available for harvesting')
            return []
        
        if hasattr(fh,'read'):
            fh = [fh]
        
        metadata = {}
        source = u'sfx://%s' % (self.getSource(),)
        
        for handle in fh:
            try:
                log.debug('%s importing from file handler' % (str(self)))
                for row in csv.reader(handle, dialect=self.dialect):
                    log.debug('%s handling a row' % (str(self),))
                    try:
                        offset = 0
                        identifier = row[self.identifier].strip()
                        
                        if not identifier:
                            log.warning('Empty identifier encountered')
                            continue
                        
                        log.debug('%s import instance id: %s' % (str(self),str(identifier),))
                        
                        instance = metadata.setdefault(identifier, set())
                        
                        for fs in self.fieldsets:
                            log.debug('rendering fieldset: %s' % (str(fs),))
                            instance.add(fs.render(source,
                                                   row[offset:offset+len(fs.fields)]))
                            offset += len(fs.fields)
                    except Exception, e:
                        log.error('Encountered an exception: %s' % (str(e)))
                        import sys, traceback
                        for line in traceback.format_exception(*sys.exc_info()):
                            log.error(line)
            except Exception, e:
                log.error('Error importing from file handle: %s' % (str(e)))
                import sys, traceback
                for line in traceback.format_exception(*sys.exc_info()):
                    log.error(line)
        
        instances = []
        for identifier, value in metadata.iteritems():
            log.debug('Creating instance for %s' % (identifier,))
            instances.append(Instance(source=source,
                                      identifier=unicode(identifier),
                                      metadata=value))
        
        return instances